package cn.iocoder.yudao.module.ai.controller.admin.jupyter;

import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.module.ai.dal.dataobject.busimodelparam.BusiModelParamDO;
import cn.iocoder.yudao.module.ai.utils.DockerClient;
import cn.iocoder.yudao.module.ai.utils.DockerTool;
import cn.iocoder.yudao.module.infra.util.StringUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.security.access.prepost.PreAuthorize;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Operation;

import javax.validation.constraints.*;
import javax.validation.*;
import javax.servlet.http.*;
import java.io.File;
import java.nio.file.Paths;
import java.util.*;
import java.io.IOException;

import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;

import static cn.iocoder.yudao.framework.common.pojo.CommonResult.error;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;

import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;

import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*;

import cn.iocoder.yudao.module.ai.controller.admin.jupyter.vo.*;
import cn.iocoder.yudao.module.ai.dal.dataobject.jupyter.JupyterDO;
import cn.iocoder.yudao.module.ai.service.jupyter.JupyterService;


@Tag(name = "管理后台 - jupyter容器管理")
@RestController
@RequestMapping("/ai/jupyter")
@Validated
@Slf4j
public class JupyterController {

    @Resource
    private JupyterService jupyterService;

    @Resource
    private DockerClient dockerClient;

    @Value("${jupyter.env-file-name}")
    private String envFile;

    @Value("${jupyter.config-file-name}")
    private String sceneFile;



    /**
     * 启动一个新jupyter容器流程：
     *  1.使用配置文件中端口范围,寻找一个未被占用的外部端口
     *  2.访问docker rest api,构建并启动jupyter容器
     *  3.1 min 轮询一次jupyter过期时间，将过期的容器回收
     *  4.创建成功后,返回访问地址
     * @param createReqVO
     * @return
     */
    @PostMapping("/create")
    @Operation(summary = "创建jupyter容器")
    @PreAuthorize("@ss.hasPermission('ai:jupyter:create')")
    public CommonResult<JupyterDO> createJupyter(@Valid @RequestBody JupyterSaveReqVO createReqVO)  {
        if(createReqVO.getExpirationTime() == 0){
            createReqVO.setExpirationTime(120);
        }
        JupyterDO jupyter = jupyterService.createJupyter(createReqVO);
        try {
            String containerId = dockerClient.createAndRunDocker(jupyter.getOpenPort() + "", jupyter.getWorkPath());
            if("errorId".equals(containerId)){
                log.info("{} 容器创建失败，并未返回containerId",jupyter.getOpenPort());
                error(CommonResult.error(500,jupyter.getOpenPort()+" 容器创建失败，并未返回containerId"));
            }else{
                jupyter.setImageId(containerId);
                jupyterService.updateById(jupyter);
            }
        }catch (RuntimeException e){
            error(CommonResult.error(500,e.getMessage()));
        }
        return success(jupyter);
    }



    /**
     * 解析Jupyter工作区内上传文件参数:
     *     1.读取工作目录下的config.py文件内容
     *     2.文件内容如下：
     *     config = {
     *         "config_id": "test1",
     *         "location": "test2",
     *         "json_url": "http://192.168.198.180:23497",
     *         "business_params": {
     *             "限制区域人员进入3": {
     *                 "area_lt": [743, 6],
     *                 "area_rb": [1275, 715],
     *                 "time_in": 1
     *             }
     *         }
     *      }
     *      3.解析 config 节点下 business_params 对象的内容
     *      4.反显business_params 内部的 key作为业务模型名称
     *      5.business_params的 value,作为默认参数名和参数值,需依次使用 instanceof 方法判断参数类型，将类型解析并返回给前端
     * @param jupyterDO
     * @return
     */
    @PostMapping("/analyzeArguments")
    @Operation(summary = "解析Jupyter工作区内上传文件参数")
    @PreAuthorize("@ss.hasPermission('ai:jupyter:analyze')")
    public CommonResult<Map<String, ConfigParame>> analyzeArguments(@Valid @RequestBody JupyterDO jupyterDO) throws IOException {
        Map resultParam = new LinkedHashMap();
        log.info("开始遍历文件夹,寻找并解析配置文件");

        java.nio.file.Path evnPath = jupyterService.findConfigFileWithWalk(Paths.get(jupyterDO.getWorkPath()),envFile);
        if(ObjectUtil.isNotEmpty(evnPath)) {
            List<BusiModelParamDO> envParams = jupyterService.parseEnvFile(evnPath.toFile().getAbsolutePath());
            resultParam.put("evnParam",envParams);
            log.info("解析 env.sh 文件：{}",JSONObject.toJSONString(envParams));
        }

        java.nio.file.Path scenePath = jupyterService.findConfigFileWithWalk(Paths.get(jupyterDO.getWorkPath()),sceneFile);
        if(ObjectUtil.isNotEmpty(scenePath)) {
            List<BusiModelParamDO> sceneParams = jupyterService.parseSceneFile(scenePath.toFile().getAbsolutePath());
            resultParam.put("scenePath",sceneParams);
            log.info("解析 scene.conf 文件：{}",JSONObject.toJSONString(sceneParams));
        }
        return success(resultParam);
    }




    /**
     * 修改Jupyter容器过期时间
     *
     * @param updateReqVO
     * @return
     */
    @PutMapping("/update")
    @Operation(summary = "更新jupyter 活跃时间")
    @PreAuthorize("@ss.hasPermission('ai:jupyter:update')")
    public CommonResult<Boolean> updateJupyter(@Valid @RequestBody JupyterSaveReqVO updateReqVO) {
        jupyterService.updateJupyter(updateReqVO);
        return success(true);
    }

    /**
     * 续期jupyter过期时间
     *
     * @param updateReqVO
     * @return
     */
    @PostMapping("/renew")
    @Operation(summary = "续期jupyter过期时间 活跃时间")
    @PreAuthorize("@ss.hasPermission('ai:jupyter:update')")
    public CommonResult<Boolean> renewJupyter(@Valid @RequestBody JupyterSaveReqVO updateReqVO) {
        JupyterDO jupyterDO = jupyterService.getJupyter(updateReqVO.getJupyterId());

        jupyterService.updateJupyter(updateReqVO);
        return success(true);
    }




    @DeleteMapping("/delete")
    @Operation(summary = "删除jupyter容器管理")
    @Parameter(name = "id", description = "编号", required = true)
    @PreAuthorize("@ss.hasPermission('ai:jupyter:delete')")
    public CommonResult<Boolean> deleteJupyter(@RequestParam("id") Integer id) {
        jupyterService.deleteJupyter(id);
        return success(true);
    }

    @GetMapping("/get")
    @Operation(summary = "获得jupyter容器管理")
    @Parameter(name = "id", description = "编号", required = true, example = "1024")
    @PreAuthorize("@ss.hasPermission('ai:jupyter:query')")
    public CommonResult<JupyterRespVO> getJupyter(@RequestParam("id") Integer id) {
        JupyterDO jupyter = jupyterService.getJupyter(id);
        return success(BeanUtils.toBean(jupyter, JupyterRespVO.class));
    }

    @GetMapping("/page")
    @Operation(summary = "获得jupyter容器管理分页")
    @PreAuthorize("@ss.hasPermission('ai:jupyter:query')")
    public CommonResult<PageResult<JupyterRespVO>> getJupyterPage(@Valid JupyterPageReqVO pageReqVO) {
        PageResult<JupyterDO> pageResult = jupyterService.getJupyterPage(pageReqVO);
        return success(BeanUtils.toBean(pageResult, JupyterRespVO.class));
    }



}